#include "nosal/core/core_error_domain.h"
#include "nosal/core/error_code.h"
#include "nosal/core/exception.h"

#include "gtest/gtest.h"

#include <type_traits>

using namespace netaos;

TEST(CoreErrorDomainTest, StaticTypeProperties)
{
    static_assert(std::is_enum<nosal::core::CoreErrorDomain::Errc>::value, "Nested type Errc is not an enum");
    static_assert(std::is_same<nosal::core::CoreErrorDomain::Errc, nosal::core::CoreErrc>::value,
        "Nested type Errc is not the expected enum");

    static_assert(
        std::is_class<nosal::core::CoreErrorDomain::Exception>::value, "Nested type Exception is not a class type");
    static_assert(std::is_base_of<nosal::core::Exception, nosal::core::CoreErrorDomain::Exception>::value,
        "Nested type Exception is not derived from nosal::core::Exception");

    static_assert(std::is_final<nosal::core::CoreErrorDomain>::value, "ErrorDomain subclass is not final");

    SUCCEED();
}

TEST(CoreErrorDomainTest, Name)
{
    constexpr nosal::core::CoreErrorDomain core;

    EXPECT_EQ(core.Name(), "Core");
}

TEST(CoreErrorDomainTest, Message)
{
    constexpr nosal::core::CoreErrorDomain core;

    nosal::core::CoreErrc err = nosal::core::CoreErrc::kInvalidArgument;
    nosal::core::ErrorDomain::CodeType num = static_cast<nosal::core::ErrorDomain::CodeType>(err);
    EXPECT_EQ(core.Message(num), "Invalid argument");

    nosal::core::ErrorDomain::CodeType invalidNum = 0x12345678;
    EXPECT_NE(core.Message(invalidNum), nullptr);
}

TEST(CoreErrorDomainTest, Throw)
{
    nosal::core::ErrorCode const ec(nosal::core::CoreErrc::kInvalidArgument);

    constexpr nosal::core::CoreErrorDomain core;
    EXPECT_THROW(core.ThrowAsException(ec), nosal::core::CoreException);
}

TEST(CoreErrorDomainTest, CoreErrorDomainAccessor)
{
    constexpr nosal::core::ErrorDomain const& core = nosal::core::GetCoreErrorDomain();

    EXPECT_EQ(core.Name(), "Core");
}

TEST(CoreErrorDomainTest, MakeErrorCodeOverload)
{
    nosal::core::ErrorDomain const& core = nosal::core::GetCoreErrorDomain();

    constexpr nosal::core::ErrorCode ec = MakeErrorCode(nosal::core::CoreErrc::kInvalidArgument, 0);

    EXPECT_EQ(ec.Domain(), core);
    EXPECT_EQ(ec.SupportData(), 0);
    EXPECT_EQ(ec.Value(), static_cast<nosal::core::ErrorDomain::CodeType>(nosal::core::CoreErrc::kInvalidArgument));
}
